<template>
  <div class="u_editor">
    <div class="editor_wrap">
      <script :id="`editor${now}`"
              type="text/plain"
              name="content"
              style="width:100%;height:80%"></script>
    </div>
    <div class="svg_wrap"
         @click.stop.prevent="showPreview = !showPreview">
      <svg-icon :className="showPreview?'hide':'show'" />
    </div>
    <div class="viewer rich_content"
         v-show="showPreview"
         v-html="content"></div>
  </div>
</template>
<script>
import * as Qiniu from 'qiniu-js'
import qiniuUploader from 'assets/upload/upload.js'
const baseToolbar = [
  [
    // 'fullscreen', // 全屏
    // 'source', // 转换html模式
    'source', // 转换html模式
    // '|',
    'undo',
    'redo',
    'bold',
    'italic',
    'underline',
    'fontborder',
    'strikethrough',
    'removeformat',
    'formatmatch',
    'blockquote',
    'pasteplain',
    'forecolor',
    'backcolor',
    'insertorderedlist',
    'insertunorderedlist',
    'selectall',
    'cleardoc',
    'rowspacingtop',
    'rowspacingbottom',
    'lineheight',
    'fontfamily',
    'fontsize',
    'indent',
    'justifyleft',
    'justifycenter',
    'justifyright',
    'justifyjustify',
    'simpleupload',
    // 'insertimage', // 多图上传
    'insertvideo', // 视频
    // 'insertaudio', // 音频
    // 'preview',
    'previewpage' // 自定义预览
  ]
]
const surveyToolbar = [
  [
    // 'fullscreen', // 全屏
    // 'source', // 转换html模式
    'source', // 转换html模式
    // '|',
    'undo',
    'redo',
    'bold',
    'italic',
    'underline',
    'fontborder',
    'strikethrough',
    'removeformat',
    'formatmatch',
    'blockquote',
    'pasteplain',
    'forecolor',
    'backcolor',
    'insertorderedlist',
    'insertunorderedlist',
    'selectall',
    'cleardoc',
    'rowspacingtop',
    'rowspacingbottom',
    'lineheight',
    'fontfamily',
    'fontsize',
    'indent',
    'justifyleft',
    'justifycenter',
    'justifyright',
    'justifyjustify',
    'simpleupload',
    // 'insertimage', // 多图上传
    // 'insertvideo', // 视频
    // 'insertaudio', // 音频
    // 'preview',
    'previewpage' // 自定义预览
  ]
]
const richToolbar = [
  [
    'fullscreen',
    'source',
    '|',
    'undo',
    'redo',
    '|',
    'bold',
    'italic',
    'underline',
    'fontborder',
    'strikethrough',
    'superscript',
    'subscript',
    'removeformat',
    'formatmatch',
    'autotypeset',
    'blockquote',
    'pasteplain',
    '|',
    'forecolor',
    'backcolor',
    'insertorderedlist',
    'insertunorderedlist',
    'selectall',
    'cleardoc',
    '|',
    'rowspacingtop',
    'rowspacingbottom',
    'lineheight',
    'pagespacing', // 自定义页边距
    '|',
    'customstyle',
    'paragraph',
    'fontfamily',
    'fontsize',
    '|',
    'directionalityltr',
    'directionalityrtl',
    'indent',
    '|',
    'justifyleft',
    'justifycenter',
    'justifyright',
    'justifyjustify',
    '|',
    'touppercase',
    'tolowercase',
    '|',
    'link',
    'unlink',
    'anchor',
    '|',
    'imagenone',
    'imageleft',
    'imageright',
    'imagecenter',
    '|',
    'simpleupload',
    'insertimage',
    'emotion',
    'scrawl',
    'insertvideo',
    'insertaudio', // 音频
    // 'music',
    'attachment',
    'map',
    // 'gmap', //谷歌地图
    'insertframe',
    'insertcode',
    'webapp',
    'pagebreak',
    'template',
    'background',
    '|',
    'horizontal',
    'date',
    'time',
    'spechars',
    'snapscreen',
    'wordimage',
    '|',
    'inserttable',
    'deletetable',
    'insertparagraphbeforetable',
    'insertrow',
    'deleterow',
    'insertcol',
    'deletecol',
    'mergecells',
    'mergeright',
    'mergedown',
    'splittocells',
    'splittorows',
    'splittocols',
    'charts',
    '|',
    'print',
    // 'preview',
    'previewpage', // 自定义预览
    'searchreplace',
    'drafts',
    'help'
  ]
]
const textToolbar = [
  [
    // 'source', // 转换html模式
    'source', // 转换html模式
    'undo',
    'redo',
    'bold',
    'italic',
    'underline',
    'fontborder',
    'strikethrough',
    // 'removeformat',
    // 'formatmatch',
    // 'blockquote',
    // 'pasteplain',
    'forecolor',
    'backcolor',
    'insertorderedlist',
    'insertunorderedlist',
    'rowspacingtop',
    'rowspacingbottom',
    'lineheight',
    'indent',
    'justifyleft',
    'justifycenter',
    'justifyright',
    'justifyjustify',
    'fontfamily',
    'fontsize'
  ]
]

export default {
  name: 'UEditor',
  props: {
    value: String,
    disabled: Boolean,
    readonly: Boolean,
    // 设置编辑器高度
    ueHeight: {
      type: Number,
      default: 200
    },
    // 是否是微信上传
    isWx: {
      type: Boolean,
      default: false
    },
    // 是否上传到企业微信
    isCpWx: {
      type: Boolean,
      default: false
    },
    // 基础工具栏:base;丰富工具栏:rich;文本工具栏:text;
    toolbarMode: {
      type: String,
      default: 'base'
    }
  },
  data () {
    return {
      now: Date.now(), // 动态的id 解决同一个页面初始化多个编辑器失败的问题
      ue: null,
      content: '',
      showPreview: false
    }
  },
  watch: {
    value: {
      handler (val) {
        this.content = val
        if (this.ue && this.ue.isReady && (!this.ue.hasContents() || this.ue.getContent() !== val)) {
          this.ue.setContent(this.content)
        }
      },
      immediate: true
    },
    content (val) {
      this.$emit('input', val)
    },
    disabled (val) {
      this.checkDisabled()
    }
  },
  methods: {
    checkDisabled () {
      if (this.disabled) {
        this.ue.setDisabled('fullscreen')
      } else {
        this.ue.setEnabled()
      }
    },
    // 文章 从正文获取摘要
    getRealContent (count) {
      let text = this.ue && this.ue.getContentTxt()
      return text.replace(/\s/g, '').substr(0, count)
    },
    getType (file) {
      let files = ['xls', 'xlsx', 'doc', 'docx', 'ppt', 'pptx', 'pdf']
      if (file.name &&
        ~file.name.indexOf('.') &&
        file.name.split('.')[1] &&
        ~files.indexOf(file.name.split('.')[1])) {
        return '.' + file.name.split('.')[1]
      } else {
        return '.' + (file.type.split('/')[1] || '')
      }
    },
    // 获取时间戳
    getTimeStamp () {
      let now = new Date()
      let Y = now.getFullYear()
      let M = '0' + (now.getMonth() + 1)
      let D = '0' + now.getDate()
      let h = '0' + now.getHours()
      let m = '0' + now.getMinutes()
      let s = '0' + now.getSeconds()
      let ms = '000' + now.getMilliseconds()
      return Y + M.substr(-2) + D.substr(-2) + h.substr(-2) + m.substr(-2) + s.substr(-2) + ms.substr(-4)
    },
    // 资源上传到七牛
    upload (file, success, error, next) {
      let timeStamp = this.getTimeStamp()
      let type = this.getType(file)
      let key = 'ueditor_' + timeStamp + type
      qiniuUploader.getUptoken().then(res => {
        if (res.data.code === 200) {
          let token = res.data.data.uptoken
          var observable = Qiniu.upload(file, key, token)
          observable.subscribe({
            next (res) {
              if (next && typeof next === 'function') next(res)
            },
            error (e) {
              if (error && typeof error === 'function') error(e)
            },
            complete (res) {
              if (success && typeof success === 'function') success(key)
            }
          })
        }
      }).catch(err => {
        this.handleError(err)
      })
    },
    // 资源上传到微信
    uploadWx (imgFile, success, error) {
      // let size = Math.floor(file.size / 1024)
      // if (size > 1024 * 1) {
      //   this.$message({
      //     message: '建议使用1MB以内的jpg、jpeg、png图片',
      //     type: 'warning'
      //   })
      //   return
      // }
      // 将需要上传的图片压缩成小于等于1M的文件
      this.compressImg(imgFile, 1, file => {
        console.log('size', file.size / (1024 * 1024))
        let size = Math.floor(file.size / (1024 * 1024))
        if (size > 1) {
          this.$message({
            message: '建议使用1MB以内的jpg、jpeg、png图片',
            type: 'warning'
          })
          return
        }
        let appid = sessionStorage.getItem('appid')
        let url = `${this.SERVICE_WECHAT}/upgrade/media/${appid}/upload/newsimg`
        let formData = new FormData()
        formData.append('file', file, file.name)
        this.posts(url, formData).then(rsp => {
          if (rsp.status === 200 || rsp.status === 201) {
            if (success && typeof success === 'function') success(rsp.data.data)
          } else {
            if (error && typeof error === 'function') error(rsp)
          }
        }).catch(e => {
          this.handleError(e)
          if (error && typeof error === 'function') error(e)
        })
      })
    },
    // 资源上传到企业微信
    uploadCpWx (imgFile, success, error) {
      // let size = Math.floor(file.size / 1024)
      // if (size > 1024 * 2) {
      //   this.$message({
      //     message: '建议使用2MB以内的jpg、png图片',
      //     type: 'warning'
      //   })
      //   return
      // }
      // 将需要上传的图片压缩成小于等于2M的文件
      this.compressImg(imgFile, 2, file => {
        console.log('size', file.size / (1024 * 1024))
        let size = Math.floor(file.size / (1024 * 1024))
        if (size > 2) {
          this.$message({
            message: '建议使用2MB以内的jpg、png图片',
            type: 'warning'
          })
          return
        }
        let url = `${this.SERVICE_CP}/media/upload/newsImg`
        let formData = new FormData()
        formData.append('file', file, file.name)
        this.posts(url, formData).then(rsp => {
          if (rsp.status === 200 || rsp.status === 201) {
            if (success && typeof success === 'function') success(rsp.data.data)
          } else {
            if (error && typeof error === 'function') error(rsp)
          }
        }).catch(e => {
          this.handleError(e)
          if (error && typeof error === 'function') error(e)
        })
      })
    },
    // 压缩图片
    compressImg (file, maxSize, success, error) {
      // 图片小于等于最大图片大小不压缩
      if (file.size <= maxSize * Math.pow(1024, 2)) {
        return success(file)
      }
      const name = file.name // 文件名
      const reader = new FileReader()
      reader.readAsDataURL(file)
      reader.onload = e => {
        const src = e.target.result

        const img = new Image()
        img.src = src
        img.onload = e => {
          const w = img.width
          const h = img.height
          // 生成canvas
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')
          // 创建属性节点
          const anw = document.createAttribute('width')
          anw.nodeValue = w
          const anh = document.createAttribute('height')
          anh.nodeValue = h
          canvas.setAttributeNode(anw)
          canvas.setAttributeNode(anh)

          // 铺底色 PNG转JPEG时透明区域会变黑色
          ctx.fillStyle = '#fff'
          ctx.fillRect(0, 0, w, h)

          ctx.drawImage(img, 0, 0, w, h)
          let quality = 1
          let fileSize = file.size / (1024 * 1024)
          console.log('fileSize', fileSize)
          quality = (maxSize / fileSize).toFixed(2)
          // quality值越小，所绘制出的图像越模糊
          const base64 = canvas.toDataURL('image/jpeg', quality) // 图片格式jpeg或webp可以选0-1质量区间

          // 返回base64转blob的值
          // console.log(`原图${(src.length / 1024).toFixed(2)}kb`, `新图${(base64.length / 1024).toFixed(2)}kb`)
          // 去掉url的头，并转换为byte
          const bytes = window.atob(base64.split(',')[1])
          // 处理异常,将ascii码小于0的转换为大于0
          const ab = new ArrayBuffer(bytes.length)
          const ia = new Uint8Array(ab)
          for (let i = 0; i < bytes.length; i++) {
            ia[i] = bytes.charCodeAt(i)
          }
          file = new Blob([ab], {type: 'image/jpeg'})
          file.name = name
          console.log(`原图${(fileSize).toFixed(2)}M`, `新图${(file.size / (1024 * 1024)).toFixed(2)}M`)
          success(file)
        }
        img.onerror = e => {
          error(e)
        }
      }
      reader.onerror = e => {
        error(e)
      }
    }
  },
  mounted () {
    // 动态获取资源域名
    let baseUrlPrefix = this.ossInfo && this.ossInfo.domain ? `${this.ossInfo.domain}/` : 'http://static.oss.yuemia.com/'
    let toolbars = []
    switch (this.toolbarMode) {
      case 'base':
        toolbars = baseToolbar
        break
      case 'rich':
        toolbars = richToolbar
        break
      case 'survey':
        toolbars = surveyToolbar
        break
      case 'text':
        toolbars = textToolbar
        break
    }
    this.ue = window.UE.getEditor(`editor${this.now}`, {
      useXM: this.toolbarMode !== 'text', // 是否使用秀米插件
      use135: this.toolbarMode !== 'text', // 135插件
      toolbars: toolbars,
      readonly: this.readonly,
      // spacing:15 (默认15)
      // 默认前缀，作用于：imageUrlPrefix、catcherUrlPrefix、videoUrlPrefix、audioUrlPrefix、fileUrlPrefix、snapscreenUrlPrefix、scrawlUrlPrefix
      baseUrlPrefix: baseUrlPrefix,
      initialFrameHeight: this.ueHeight, // 初始化默认高度
      autoHeightEnabled: false, // 编辑器自动高
      catchRemoteImageEnable: true, // 设置是否抓取远程图片
      catcherFieldName: 'catcherField',
      snapscreenActionName: 'snapscreenAction',
      // 以下有默认值
      imageAllowFiles: ['.png', '.jpg', '.jpeg', '.gif', '.bmp'],
      videoAllowFiles: ['.mp4'],
      // 默认：[".mp3", ".wma", ".wav", ".amr"]
      audioAllowFiles: ['.mp3'],
      fileAllowFiles: ['xls', 'xlxs', 'doc', 'docx', 'ppt', 'pptx', 'pdf'],
      videoPoster: require('./img/video_placeholder.jpg'), // 视频默认封面
      imageUrlPrefix: baseUrlPrefix, // 拖拽上传需要不可以注释
      // catcherUrlPrefix: 'http://static.oss.yuemia.com/', // 抓取
      // videoUrlPrefix: 'http://static.oss.yuemia.com/',
      // audioUrlPrefix: 'http://qn.gdl.yuemia.com/', // 音频
      // fileUrlPrefix: 'http://static.oss.yuemia.com/', // 附件上传
      // snapscreenUrlPrefix: 'http://static.oss.yuemia.com/', // 截图（未处理）
      // scrawlUrlPrefix: 'http://static.oss.yuemia.com/', // 涂鸦
      /**
       * @method: qnUpload
       * @name: 编辑器上传处理
       * @description: 处理uEditor中的图片，视频等上传
       * @param {File} file 上传的文件
       * @param {Function} success 成功回调
       * @param {Function} error 失败回调
       * @param {Function} next 进度回调
       * @param {String} type 文件类型 [image,video,file]
       * @return:
       */
      _upload: ({ file, success, error, next }) => {
        let fileType = file.type
        // 判断上传的是图片且是微信上传，资源上传到微信
        if (fileType.indexOf('image/') !== -1 && this.isWx) {
          this.uploadWx(file, success, error)
        // 判断如果是图片并且是企业微信上传，资源上传到企业微信
        } else if (fileType.indexOf('image/') !== -1 && this.isCpWx) {
          this.uploadCpWx(file, success, error)
        // 否则上传到七牛
        } else {
          this.upload(file, success, error, next)
        }
      },
      // 自定义预览功能
      _previewpage: () => {
        this.showPreview = !this.showPreview
      }
    })
    this.ue && this.ue.ready(() => {
      this.ue.setContent(this.value)
      this.checkDisabled() // 编辑器是否可编辑
    })
    this.ue.addListener('contentChange', () => {
      setTimeout(() => {
        this.content = this.ue.getContent()
        this.$emit('contentChange', this.ue.getContent())
      })
    })
  },
  destroyed () {
    this.ue && this.ue.destroy()
  }
}
</script>
<style>
  .viewer * {
    max-width: 100%;
  }
</style>
<style lang="stylus" scoped>
.u_editor
  position relative
  display flex
  padding-bottom 30px
  .viewer
    position relative
    overflow-x hidden
    overflow-y auto
    box-sizing border-box
    margin-left 15px
    padding 1em
    width 375px
    // height 800px
    border 1px solid #d4d4d4
    border-radius 4px
    &::-webkit-scrollbar /* 滚动条整体样式 */
      width 6px /* 高宽分别对应横竖滚动条的尺寸 */
      height 6px
    &::-webkit-scrollbar-thumb /* 滚动条里面小方块 */
      border-radius 3px
      background rgba(144, 147, 153, 0.3)
      // -webkit-box-shadow inset 0 0 5px rgba(0, 0, 0, 0.2)
    &::-webkit-scrollbar-track /* 滚动条里面轨道 */
      // -webkit-box-shadow inset 0 0 5px rgba(0,0,0,0.2)
      // border-radius 10px
      background #fff
  .svg_wrap
    position absolute
    top 30px
    left -10px
    z-index 99
    display flex
    justify-content center
    align-items center
    width 30px
    height 30px
    border-radius 50%
    background-color rgba(0, 0, 0, 0.2)
    cursor pointer
    transform translate(-100%, 0)
    display none
.editor_wrap
  flex 1
  // max-width 700px
  width 0
  // height 800px
</style>
